<?php

namespace Crc\Entity;

abstract class AbstractEntity
{
    protected function propertyExists($name)
    {
        if (!property_exists(get_class($this), $name)) return false;
        $reflection = new \ReflectionProperty(get_class($this), $name);
        if (!$reflection->isProtected()) return false;

        return true;
    }

    public function get($property)
    {
        $getFunction = 'get' . ucfirst($property);
        return $this->$getFunction();
    }

    /**
     * Magic method implements get, set, unset, has
     *
     * @param  string $key
     * @param  array $args
     * @return mixed
     * @throws Exception for invalid method
     */
    public function __call($method, $args)
    {
        switch (substr($method, 0, 3))
        {
            case 'get' :
                $key = lcfirst(substr($method,3));
                if ($this->propertyExists($key)) {
                    return $this->$key;
                }
                throw new \Exception("Invalid variable in class " . get_class($this) . "::" . $key . "");
                break;

            case 'set' :
                $key = lcfirst(substr($method,3));
                if ($this->propertyExists($key)) {
                    $value = isset($args[0]) ? $args[0] : null;
                    $this->$key = $value;
                    return $this;
                }
                throw new \Exception("Invalid variable in class " . get_class($this) . "::" . $key . "");
                break;

            case 'uns' :
                if (substr($method, 0, 5) == 'unset') {
                    $key = lcfirst(substr($method,5));
                    if ($this->propertyExists($key)) {
                        unset($this->$key);
                        return $this;
                    }
                    throw new \Exception("Invalid variable in class " . get_class($this) . "::" . $key . "");
                }
                break;

            case 'has' :
                $key = lcfirst(substr($method,3));
                if ($this->propertyExists($key)) {
                    $result = isset($this->$key);
                }
                throw new \Exception("Invalid variable in class " . get_class($this) . "::" . $key . "");
                break;
       }

        throw new Exception("Invalid method " . get_class($this) . "::" . $method . "(" . print_r($args,1) . ")");
    }

    /**
     * Restrics direct access to class protected properties
     *
     * @param  string $key  The user-specified property name.
     * @return void
     * @throws Exception if the $key is not a property in the class.
     */
    public function __get($key)
    {
        if (!$this->propertyExists($key)) {
            throw new \Exception("Invalid variable in class " . get_class($this) . "::" . $key . "");
        }

        throw new \Exception("Access denied to variable in class " . get_class($this) . "::" . $key . "");
    }

    /**
     * Restrics direct access to class protected properties
     *
     * @param  string $key        The property name.
     * @param  mixed  $value      The value for the property.
     * @return void
     * @throws Exception if the $key is not a property in the class.
     */
    public function __set($key, $value)
    {
        if (!$this->propertyExists($key)) {
            throw new \Exception("Invalid variable in class " . get_class($this) . "::" . $key . "");
        }

        throw new \Exception("Access denied to variable in class " . get_class($this) . "::" . $key . "");
    }

    public function __toString()
    {
        if ($this->propertyExists('name')) {
            return $this->getName();
        }

        trigger_error("Method __toString not defined in class " . get_class($this), E_USER_ERROR);
    }
}